use std::collections::HashMap;
use std::error::Error;
use std::str::FromStr;
use crate::json::error::ParserError;
use crate::json::Json;
use crate::json::lexer::{Lexer, TokenType};


pub struct Parser
{
    m_lexer: Lexer,
}

impl Parser {
    pub fn new() -> Parser {
        Parser { m_lexer: Lexer::new() }
    }

    pub fn load(&mut self, code: &str) -> Result<Json, Box<dyn Error>> {
        self.m_lexer.clear();
        self.m_lexer.scan(code)?;
        let res = self.parse_json()?;
        return Ok(res);
    }

    fn forward_token(&mut self, tt: TokenType) -> Result<(), ParserError> {
        if self.m_lexer.view_next().get_type() == tt {
            self.m_lexer.next();
            Ok(())
        } else {
            Err(ParserError::new(self.m_lexer.view_next().clone()))
        }
    }

    pub fn parse_json(&mut self) -> Result<Json, ParserError> {
        match self.m_lexer.view_next().get_type() {
            TokenType::LeftBrace => {
                let temp = self.parse_object()?;
                Ok(temp)
            }
            TokenType::Number => {
                let temp = self.parse_number()?;
                Ok(temp)
            }
            TokenType::LeftBracket => {
                let temp = self.parse_array()?;
                Ok(temp)
            }
            TokenType::Bool => {
                let temp = self.parse_bool()?;
                Ok(temp)
            }
            TokenType::String => {
                let temp = self.parse_string()?;
                Ok(temp)
            }
            TokenType::TokenNull => {
                let temp = self.parse_null()?;
                Ok(temp)
            }
            _ => {
                Err(ParserError::new(self.m_lexer.view_next().clone()))
            }
        }
    }


    fn parse_object(&mut self) -> Result<Json, ParserError> {
        self.forward_token(TokenType::LeftBrace)?;
        let mut map1 = HashMap::new();
        self.parse_pairs(&mut map1)?;
        self.forward_token(TokenType::RightBrace)?;
        return Ok(Json::from_object(map1));
    }

    fn parse_array(&mut self) -> Result<Json, ParserError> {
        self.forward_token(TokenType::LeftBracket)?;
        let mut arr = Vec::new();
        self.parse_objects(&mut arr)?;
        self.forward_token(TokenType::RightBracket)?;
        return Ok(Json::from_array(arr));
    }

    fn parse_objects(&mut self, arr: &mut Vec<Json>) -> Result<(), ParserError> {
        if self.m_lexer.view_next().get_type() == TokenType::RightBracket {
            return Ok(());
        }
        let current_value = self.parse_json()?;
        arr.push(current_value);
        if self.m_lexer.view_next().get_type() == TokenType::RightBracket {
            return Ok(());
        }
        self.forward_token(TokenType::Comma)?;
        self.parse_objects(arr)?;
        return Ok(());
    }

    fn parse_pairs(&mut self, map: &mut HashMap<String, Json>) -> Result<(), ParserError> {
        if self.m_lexer.view_next().get_type() == TokenType::RightBrace {
            return Ok(());
        }
        self.forward_token(TokenType::String)?;
        let current_key = self.m_lexer.view_current().get_str().to_string();
        self.forward_token(TokenType::Colon)?;
        let current_value = self.parse_json()?;
        map.insert(current_key, current_value);
        if self.m_lexer.view_next().get_type() == TokenType::RightBrace {
            return Ok(());
        }
        self.forward_token(TokenType::Comma)?;
        self.parse_pairs(map)?;
        return Ok(());
    }

    fn parse_number(&mut self) -> Result<Json, ParserError> {
        self.forward_token(TokenType::Number)?;
        let num = self.m_lexer.view_current();
        if let None = num.get_str().find('.') {
            // 未找到
            Ok(Json::from_integer(i32::from_str(num.get_str()).unwrap()))
        } else {
            Ok(Json::from_float(f64::from_str(num.get_str()).unwrap()))
        }
    }

    fn parse_string(&mut self) -> Result<Json, ParserError> {
        self.forward_token(TokenType::String)?;
        Ok(Json::from_string(self.m_lexer.view_current().get_str()))
    }

    fn parse_null(&mut self) -> Result<Json, ParserError> {
        self.forward_token(TokenType::TokenNull)?;
        Ok(Json::new())
    }

    fn parse_bool(&mut self) -> Result<Json, ParserError> {
        self.forward_token(TokenType::Bool)?;
        if self.m_lexer.view_current().get_str() == "true" {
            Ok(Json::from_bool(true))
        } else {
            Ok(Json::from_bool(false))
        }
    }
}

#[cfg(test)]
mod test_parser {
    use crate::json::Json;
    use crate::json::parser::Parser;

    #[test]
    fn test_parser_create() {
        let _ = Parser::new();
    }

    #[test]
    fn test_parser_simple() {
        let mut p1 = Parser::new();
        let mut v1 = p1.load("true").unwrap();
        assert_eq!(v1, Json::from_bool(true));
        println!("{}", v1);
        v1 = p1.load("10").unwrap();
        assert_eq!(v1, Json::from_integer(10));
        v1 = p1.load("10.0").unwrap();
        assert_eq!(v1, Json::from_float(10.0));
        v1 = p1.load("\"string\"").unwrap();
        assert_eq!(v1, Json::from_string("string"));
        v1 = p1.load("null").unwrap();
        assert_eq!(v1, Json::new());
    }

    #[test]
    fn test_parser_array() {
        let mut p1 = Parser::new();
        let v1 = p1.load("[10,true,false,null,\"hello\",1.1]").unwrap();
        println!("{}", v1)
    }

    #[test]
    fn test_parser_object() {
        let mut p1 = Parser::new();
        let v1 = p1.load("{\"key1\":10,\"key2\":false,\"key3\":null,\"key4\":1.1,\"key5\":\"hello\"}").unwrap();
        println!("{}", v1);
    }

    #[test]
    fn test_parser_complex() {
        let mut p1 = Parser::new();
        let v1 = p1.load("{\"key1\":10,\"key2\":false,\"key3\":null,\"key4\":1.1,\"key5\":\"hello\",\"key6\":[10,true,false,null,\"hello\",1.1],\"key7\":{\"key1\":10,\"key2\":false,\"key3\":null,\"key4\":1.1,\"key5\":\"hello\"}}").unwrap();
        println!("{}", v1);
    }
}